﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RelateTransactionViewModelTests.cs" company="Concept Architecture">
//   (c) 2010 Muhammad Umer Farooq
// </copyright>
// <summary>
//   Defines the <seealso cref="Hisaab.Client.Test.ViewModel.RelateTransactionViewModelTests" /> type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Hisaab.Client.Test.ViewModel
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Business.Entities;
    using Business.Interfaces;

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    using Windows.Client.ViewModel;
    using Windows.Common;
    using Transaction = Windows.Client.Model.Transaction;

    /// <summary>
    /// Defines the <seealso cref="Hisaab.Client.Test.ViewModel.RelateTransactionViewModelTests"/> type.
    /// </summary>
    [TestClass, Ignore]
    public class RelateTransactionViewModelTests
    {
        /// <summary>
        /// Mock Service Locator
        /// </summary>
        private MockServiceLocator _mockServiceLocator;

        /// <summary>
        /// Mock Account Manager
        /// </summary>
        private Mock<IAccountManager> _mockAccountManager;

        /// <summary>
        /// Mock Window Dialog Service
        /// </summary>
        private Mock<IWindowDialogService> _mockDialogService;

        /// <summary>
        /// Mock Transaction Manager
        /// </summary>
        private Mock<ITransactionManager> _mockTransactionManager;

        /// <summary>
        /// Mock session
        /// </summary>
        private Mock<ISession> _mockSession;

        /// <summary>
        /// Initailizes the specified test.
        /// </summary>
        [TestInitialize]
        public void TestInitailize()
        {
            _mockServiceLocator = new MockServiceLocator();

            _mockAccountManager = new Mock<IAccountManager>();
            _mockTransactionManager = new Mock<ITransactionManager>();
            _mockDialogService = new Mock<IWindowDialogService>();
            _mockSession = new Mock<ISession>();

            _mockServiceLocator.SetInjection(_mockAccountManager.Object);
            _mockServiceLocator.SetInjection(_mockTransactionManager.Object);
            _mockServiceLocator.SetInjection(_mockDialogService.Object);
            _mockServiceLocator.SetInjection(_mockSession.Object);
        }

        /// <summary>
        /// Constructors the should throw if the source transaction is null.
        /// </summary>
        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorShouldThrowIfTheSourceTransactionIsNull()
        {
            new RelateTransactionViewModel(null);
        }

        /// <summary>
        /// Constructors the should not throw if the source transaction is not null.
        /// </summary>
        [TestMethod]
        public void ConstructorShouldNotThrowIfTheSourceTransactionIsNotNull()
        {
            new RelateTransactionViewModel(new Transaction { Date = new DateTime(2000, 05, 06) });
        }

        /// <summary>
        /// Constructors the should throw if account manager is null.
        /// </summary>
        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorShouldThrowIfAccountManagerIsNull()
        {
            new RelateTransactionViewModel(new Transaction(), null, _mockTransactionManager.Object, _mockSession.Object);
        }

        /// <summary>
        /// Constructors the should throw if transaction manager is null.
        /// </summary>
        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorShouldThrowIfTransactionManagerIsNull()
        {
            new RelateTransactionViewModel(new Transaction(), _mockAccountManager.Object, null, _mockSession.Object);
        }

        /// <summary>
        /// Constructors the should set the dates accordingly.
        /// </summary>
        [TestMethod]
        public void ConstructorShouldSetTheDatesAccordingly()
        {
            var transaction = new Transaction { Date = DateTime.Today };
            var vm = new RelateTransactionViewModel(transaction, _mockAccountManager.Object, _mockTransactionManager.Object, _mockSession.Object);

            Assert.AreEqual(DateTime.Today.AddDays(-2), vm.StartDate);
            Assert.AreEqual(DateTime.Today.AddDays(2), vm.EndDate);
        }

        /// <summary>
        /// Accountses the property should get account list from business.
        /// </summary>
        [TestMethod]
        public void AccountsPropertyShouldGetAccountListFromBusiness()
        {
            var accountsList = new List<Account>
                                   {
                                       new Account { AccountId = 1, AccountType = 2, Name = "Account 1" },
                                       new Account { AccountId = 2, AccountType = 2, Name = "Account 2" }
                                   };

            _mockAccountManager.Setup(x => x.List(It.Is<Account>(a => a.UserId == 67), null, null)).Returns(accountsList);
            _mockSession.SetupGet(x => x.LoggedUser).Returns(67).Verifiable();

            var vm = new RelateTransactionViewModel(new Transaction { Date = new DateTime(2000, 05, 06) });
            var accounts = vm.Accounts;

            Assert.AreEqual(accountsList.Count, accounts.Count);
            _mockAccountManager.Verify(x => x.List(It.Is<Account>(a => a.UserId == 67), null, null), Times.Once());
            _mockSession.VerifyAll();
        }

        /// <summary>
        /// Accountses the property should get account list from business once.
        /// </summary>
        [TestMethod]
        public void AccountsPropertyShouldGetAccountListFromBusinessOnce()
        {
            var accountsList = new List<Account>
                                   {
                                       new Account { AccountId = 1, AccountType = 2, Name = "Account 1" },
                                       new Account { AccountId = 2, AccountType = 2, Name = "Account 2" }
                                   };

            _mockAccountManager.Setup(x => x.List(It.Is<Account>(a => a.UserId == 15), null, null)).Returns(accountsList);
            _mockSession.SetupGet(x => x.LoggedUser).Returns(15).Verifiable();

            var vm = new RelateTransactionViewModel(new Transaction { Date = new DateTime(2000, 05, 06) });
            var accounts = vm.Accounts;

            Assert.IsNotNull(accounts);
            accounts = vm.Accounts;

            Assert.AreEqual(accountsList.Count, accounts.Count);
            _mockAccountManager.Verify(x => x.List(It.Is<Account>(a => a.UserId == 15), null, null), Times.Once());
            _mockSession.VerifyAll();
        }

        /// <summary>
        /// Propertieses the should raise notify property changed.
        /// </summary>
        [TestMethod]
        public void PropertiesShouldRaiseNotifyPropertyChanged()
        {
            var viewModel = new RelateTransactionViewModel(new Transaction { Date = DateTime.Today });

            var tester = new NotifyPropertyChangedTester(viewModel);

            Assert.AreEqual(0, tester.Changes.Count, "Changes count was wrong.");

            viewModel.SelectedAccount = 2;
            viewModel.SelectedTransaction = new Transaction();
            viewModel.StartDate = new DateTime(2000, 6, 8);
            viewModel.EndDate = new DateTime(2001, 6, 8);

            Assert.AreEqual(4, tester.Changes.Count, "Changes count was wrong.");

            tester.AssertChange(0, "SelectedAccount");
            tester.AssertChange(1, "SelectedTransaction");
            tester.AssertChange(2, "StartDate");
            tester.AssertChange(3, "EndDate");
        }

        /// <summary>
        /// Queries the command should return A delegate to load transactions.
        /// </summary>
        [TestMethod]
        public void QueryCommandShouldReturnADelegate()
        {
            var viewModel = new RelateTransactionViewModel(new Transaction { Date = DateTime.Today });
            var command = viewModel.QueryCommand;
            Assert.IsNotNull(command);
        }

        /// <summary>
        /// Loads the transactions should load transactions from business with correct arguments.
        /// </summary>
        [TestMethod]
        public void LoadTransactionsShouldLoadTransactionsFromBusinessWithCorrectArguments()
        {
            var transaction = new Transaction { Date = DateTime.Today };
            var startDate = new DateTime(2001, 01, 05);
            var endDate = new DateTime(2001, 02, 05);
            var transactionFilter = new TransactionFilter
                                        {
                                            SortBy = SortByType.Date,
                                            OrderBy = OrderByType.Ascending,
                                            StartDate = startDate,
                                            EndDate = endDate
                                        };
            _mockTransactionManager
                .Setup(x => x.FilteredList(transactionFilter, 56))
                .Returns(
                    new List<Business.Entities.Transaction> { new Business.Entities.Transaction(), new Business.Entities.Transaction() });
            var viewModel = new RelateTransactionViewModel(transaction)
                                {
                                    SelectedAccount = 56,
                                    StartDate = startDate,
                                    EndDate = endDate
                                };
            viewModel.LoadTransactions();

            _mockTransactionManager.Verify(
                x => x.FilteredList(It.Is<TransactionFilter>(
                    f =>
                    f.SortBy == SortByType.Date && f.OrderBy == OrderByType.Ascending && f.StartDate == startDate &&
                    f.EndDate == endDate), 56),
                Times.Once());
        }

        /// <summary>
        /// Loads the transactions should set transaction as read from business layer.
        /// </summary>
        [TestMethod]
        public void LoadTransactionsShouldSetTransactionAsReadFromBusinessLayer()
        {
            var transaction = new Transaction { TransactionId = 34, Date = DateTime.Today };
            var transactions = new List<Business.Entities.Transaction>
                                   {
                                       new Business.Entities.Transaction { TransactionId = 35, Account = 56 }
                                   };
            _mockTransactionManager.Setup(x => x.FilteredList(It.IsAny<TransactionFilter>(), It.IsAny<int>()))
                .Returns(transactions);

            var viewModel = new RelateTransactionViewModel(transaction) { SelectedAccount = 56 };
            viewModel.StartDate = viewModel.EndDate = DateTime.Now;
            viewModel.LoadTransactions();

            Assert.AreEqual(transactions.Count, viewModel.Transactions.Count);
        }

        /// <summary>
        /// Loads the transactions should remove source transaction from list of transaction.
        /// </summary>
        [TestMethod]
        public void LoadTransactionsShouldRemoveSourceTransactionFromListOfTransaction()
        {
            var transaction = new Transaction { TransactionId = 35, Date = DateTime.Today };
            var transactions = new List<Business.Entities.Transaction>
                                   {
                                       new Business.Entities.Transaction { TransactionId = 35, Account = 56 },
                                       new Business.Entities.Transaction { TransactionId = 36, Account = 56 }
                                   };
            _mockTransactionManager.Setup(x => x.FilteredList(It.IsAny<TransactionFilter>(), It.IsAny<int>()))
                .Returns(transactions);

            var viewModel = new RelateTransactionViewModel(transaction) { SelectedAccount = 56 };
            viewModel.StartDate = viewModel.EndDate = DateTime.Now;
            viewModel.LoadTransactions();

            Assert.AreEqual(1, viewModel.Transactions.Count);
            Assert.AreEqual(0, viewModel.Transactions.Where(x => x.TransactionId == 35).Count());
        }

        /// <summary>
        /// Determines whether this instance [can load transactions should return false if no account selected].
        /// </summary>
        [TestMethod]
        public void CanLoadTransactionsShouldReturnFalseIfNoAccountSelected()
        {
            var transaction = new Transaction { Date = DateTime.Today };
            var viewModel = new RelateTransactionViewModel(transaction) { SelectedAccount = 0 };
            Assert.IsFalse(viewModel.CanLoadTransaction());
        }

        /// <summary>
        /// Determines whether this instance [can load transactions should return true if some account selected].
        /// </summary>
        [TestMethod]
        public void CanLoadTransactionsShouldReturnTrueIfSomeAccountSelected()
        {
            var transaction = new Transaction { Date = DateTime.Today };
            var viewModel = new RelateTransactionViewModel(transaction) { SelectedAccount = 5 };
            Assert.IsTrue(viewModel.CanLoadTransaction());
        }

        /// <summary>
        /// Called when [ok dialog should relate source and selected transactions].
        /// </summary>
        [TestMethod]
        public void OnOkDialogShouldRelateSourceAndSelectedTransactions()
        {
            var sourceTransaction = new Transaction { TransactionId = 234, Date = DateTime.Today };
            var selectedTransaction = new Transaction { TransactionId = 214, Date = DateTime.Today };
            var viewModel = new RelateTransactionViewModel(sourceTransaction) { SelectedTransaction = selectedTransaction };
            var result = viewModel.OnOkDialog();
            Assert.IsTrue(result.HasValue);
            Assert.IsTrue(result.Value);
            _mockTransactionManager.Verify(x => x.RelateTransactions(234, 214), Times.Once());
        }

        /// <summary>
        /// Determines whether this instance [can ok comand should return false if no transaction selected].
        /// </summary>
        [TestMethod]
        public void CanOkComandShouldReturnFalseIfNoTransactionSelected()
        {
            var transaction = new Transaction { Date = DateTime.Today };
            var viewModel = new RelateTransactionViewModel(transaction) { SelectedTransaction = null };
            Assert.IsFalse(viewModel.CanOkComand());
        }

        /// <summary>
        /// Determines whether this instance [can ok comand should return true if transaction selected].
        /// </summary>
        [TestMethod]
        public void CanOkComandShouldReturnTrueIfTransactionSelected()
        {
            var transaction = new Transaction { Date = DateTime.Today };
            var viewModel = new RelateTransactionViewModel(transaction) { SelectedTransaction = transaction };
            Assert.IsTrue(viewModel.CanOkComand());
        }
    }
}